/**
 * 
 */
package uk.ac.ebi.velvet.config;

import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.NotImplementedException;

import uk.ac.ebi.curtain.utils.data.FileType;
import uk.ac.ebi.curtain.utils.data.ReadType;
import uk.ac.ebi.curtain.utils.file.FileInfo;
import uk.ac.ebi.velvet.processor.StatisticsProcessor.StatisticHint;

/**
 * @author mhaimel
 *
 */
public class VelvetArgs implements Serializable {
	private static final double _INSERT_LENGTH_SD = 0.1;
	//	private static final int DEFAULT_CATEGORY = 0;
	public static final String STARTPOINT_SUPERCONTIG = "SUPER_CTG";
	private StatisticHint hint = null;
	private String startpoint = null;
	private List<FileInfo> contigFiles;
	private List<FileInfo> readFiles;
	private List<FileInfo> shortPairedFiles;
	private List<FileInfo> mapViewFiles;
	private final File workingDir;
	private Map<Integer, Integer> cat2InsertLength = new HashMap<Integer, Integer>();
	private Map<Integer, Integer> cat2InsertLengthSd = new HashMap<Integer, Integer>();
	private Map<FileInfo, Integer> fileInfo2cat = new HashMap<FileInfo, Integer>();
	private Map<File, FileInfo> file2InfoIdx = new HashMap<File, FileInfo>();
	private Integer kmer = null;
	private Integer minPairCount = 5;
	
	public VelvetArgs(File workingDir) {
		this(workingDir,null);
	}

	private void add2Idx(FileInfo info){
		file2InfoIdx.put(info.getFile(), info);
	}
	
	public FileInfo getFileinfoForFile(File file) {
		return file2InfoIdx.get(file);
	}
	
	public VelvetArgs(File workingDir,FileInfo referenceFile) {
		super();
		this.workingDir = workingDir;
		this.contigFiles = new ArrayList<FileInfo>();
		this.shortPairedFiles = new ArrayList<FileInfo>();
		this.readFiles = new ArrayList<FileInfo>();
		this.mapViewFiles = new ArrayList<FileInfo>();
		if(null != referenceFile){
			addContigFile(referenceFile);
		}
	}
	
	public void addReadFile(Integer category, FileInfo ... fileArr){
		for(FileInfo fi : fileArr){
			if(fi.getReadType().equals(ReadType.Short)){
				this.readFiles.add(fi);
				add2Idx(fi);
			} else if(fi.getReadType().equals(ReadType.ShortPaired)){
				addShortPairedFiles(category, fi);
			} else {
				throw new NotImplementedException(
						"File info not supported: " + fi);
			}
		}
	}
	public void addReadFile(Integer category, FileType type, ReadType rType, File ... fileArr){
		for(File f : fileArr){
			addReadFile(category,new FileInfo(f,type, rType));
		}
	}	
	public void addMapViewFile(FileInfo ... fileArr){
		this.mapViewFiles.addAll(Arrays.asList(fileArr));
	}
	public void addMapViewFile(FileType type, ReadType rType, File ... fileArr){
		for(File f : fileArr){
			addMapViewFile(new FileInfo(f,type,rType));
		}
	}
	
	public void addContigFile(FileInfo ... fileArr){
		for(FileInfo fi : fileArr){
			this.contigFiles.add(fi);
			add2Idx(fi);
		}
	}
	public void addContigFile(FileType type, File ... fileArr){
		for(File f : fileArr){
			if(null != f){
				addContigFile(new FileInfo(f,type,ReadType.Contig));
			}
		}
	}

	public List<FileInfo> getContigFiles() {
		return contigFiles;
	}
	
	public Collection<FileInfo> getReadFiles() {
		return readFiles;
	}
	public void addShortPairedFiles(Integer category, FileInfo ... infoArr){
		for(FileInfo fi : infoArr){
			this.shortPairedFiles.add(fi);
			this.fileInfo2cat.put(fi, category);
			add2Idx(fi);
		}
	}
	public Collection<FileInfo> getShortPairedFiles() {
		return shortPairedFiles;
	}

	public List<FileInfo> getMapViewFiles() {
		return mapViewFiles;
	}

	public File getWorkingDir() {
		return workingDir;
	}
	
	public File getMaqTempDir(){
		return new File(workingDir,"maq-temp");
	}
	
	public File getContigMappingFile(){
		return new File(workingDir,"ContigMapping.txt");
	}
	public File getReadMappingFile(){
		return new File(workingDir,"ReadsMapping.txt");
	}
	public File getShortPairedMappingFile(){
		return new File(workingDir,"ShortPairedMapping.txt");
	}
	public File getUnmappedReadFile(){
		return new File(workingDir,"unmapped.reads.fa");		
	}
	public File getUnmappedShortPairedFile(){
		return new File(workingDir,"unmapped.shortPaired.fa");		
	}	
	public File getSuperContigDir(){
		return new File(workingDir,"super");
	}
	public Integer getInsertLength(Integer cat) {
		return this.cat2InsertLength.get(cat);
	}

	public Integer getInsertLengthCategory(FileInfo info) {
		return this.fileInfo2cat.get(info);
	}
	public Collection<Integer> getInserLengthCategories(){
		return new HashSet<Integer>(this.cat2InsertLength.keySet());
	}
	public Integer getInsertLength(FileInfo info) {
		Integer cat =getInsertLengthCategory(info);
		Integer insLen = null;
		if(null != cat){
			insLen = this.cat2InsertLength.get(cat);
		}
		return insLen;
	}
	public Integer getInsertLengthSd(FileInfo info) {
		Integer cat =getInsertLengthCategory(info);
		Integer sigma = null;
		if(null != cat){
			sigma = this.cat2InsertLengthSd.get(cat);
		}
		if(null == sigma){
			sigma = Double.valueOf(getInsertLength(cat)*_INSERT_LENGTH_SD).intValue();
			this.cat2InsertLengthSd.put(cat, sigma);
		}
		return sigma;
	}
	public void setInsertLength(Integer cat, Integer insertLength) {
		this.cat2InsertLength.put(cat, insertLength);
	}
	public void setKmer(Integer kmer) {
		this.kmer = kmer;
	}
	public Integer getKmer() {
		return kmer ;
	}
	public StatisticHint getHint() {
		return this.hint;
	}
	public void setHint(StatisticHint hint) {
		this.hint = hint;
	}
	public void setStartpoint(String startpoint) {
		this.startpoint = startpoint;
	}
	public String getStartpoint() {
		return startpoint;
	}
	public Integer getMinPairCount() {
		return minPairCount;
	}
	public void setMinPairCount(Integer minPairCount) {
		this.minPairCount = minPairCount;
	}
}

